/******************************************************************************
* 文件名 	：bsp_math
* 作者	  ：菜菜的菠萝头
* 版本	  ：V1.0.0
* 日期	  ：2023/10.11
* 文件作用：常用算法
*
******************************************************************************
* 注意事项：
*1、注意使用方法。
*2、大部分由AI生成，用户自行验证。
*****************************************************************************/
#include "bsp_math.h"

/**
 * 将uint8_t数组转换为对应的十六进制字符串表示
 * @param src 源数组指针
 * @param srcLen 源数组长度
 * @param dest 目标字符串缓冲区指针
 * @param destSize 目标缓冲区大小（应至少为srcLen*2）
 * @return 转换后的字符串长度（不包括终止符），如果缓冲区不足则返回0
 */
uint16_t MathBspUint8ArrayToHexString(const uint8_t *src, size_t srcLen, char *dest, size_t destSize)
{
	if(src == NULL || dest == NULL || destSize < srcLen * 2)
	{
		return 0;
	}

	const char hexChars[] = "0123456789ABCDEF";
	uint16_t destIdx = 0;

	for(uint16_t i = 0; i < srcLen; i++)
	{
		// 高4位
		dest[destIdx++] = hexChars[(src[i] >> 4) & 0x0F];
		// 低4位
		dest[destIdx++] = hexChars[src[i] & 0x0F];
	}

	return destIdx;
}

//0数据相同，1数据不同
uint8_t MathBspStrCompareHex(uint8_t* data_in,uint8_t hex,uint16_t len)
{
	for(uint16_t i = 0u;i < len;i++)
	{
		if(data_in[i] != hex)
		{
			return 1u;
		}else{}
	}
	return 0u;
}

/* CRC16计算函数 */
uint16_t MathBspCrc16Calculate(const uint8_t *data, uint16_t length) 
{
	uint16_t crc = 0;
	uint16_t i, j;
	
	for (i = 0; i < length; i++) 
	{
		crc ^= (uint16_t)data[i] << 8;
		for (j = 0; j < 8; j++) 
		{
			if (crc & 0x8000)
				crc = (crc << 1) ^ 0x1021;
			else
				crc <<= 1;
		}
	}
	return crc;
}
uint8_t MathBspSumCheck(uint8_t* data,uint16_t len)
{
	uint8_t ret = 0;

	for(uint16_t i=0;i<len;i++)
	{
		ret += data[i];
	}
	
	return ret;
}

void MathBspStrCopy(uint8_t* data_out,const uint8_t* data_in,uint16_t len)
{
	uint16_t i;

	for(i=0;i<len;i++)
	{
		data_out[i] = data_in[i];
	}
}

uint16_t MathBspStrCharLenth(uint8_t* data_in,uint16_t len)
{
	uint16_t i;
	for(i = 0u;i < len;i++)
	{
		if(data_in[i]=='\0')
		{
			break;
		}
	}
	return i;
}

void MathBspStrInit(uint8_t* data_out,const uint8_t data,uint16_t len)
{	
	uint16_t i;

	for(i=0;i<len;i++)
	{
		data_out[i] = data;
	}
}
//计算一行字符串长度
uint16_t MathBspOneLineCharLenth(uint8_t* data_in,uint16_t len)
{
	uint16_t i;
	for(i = 0u;i < len;i++)
	{
		if(data_in[i]=='\0' || data_in[i]=='\n')
		{
			break;
		}
	}
	return i;
}

void MathBspBcdToHexU8(uint8_t* data_out,const uint8_t* data_in,uint16_t len)
{
	uint16_t i;

	for(i=0;i<len;i++)
	{
		data_out[i] = (data_in[i]&0x0f)%10 + ((data_in[i]>>4)%10)*10;
	}
}

void MathBspHexToBcdU8(uint8_t* data_out,const uint8_t* data_in,uint16_t len)
{
	uint8_t hex = 0u;
	uint16_t i;

	for(i=0;i<len;i++)
	{
		hex = data_in[i];
		data_out[i] = hex%10;
		data_out[i] += (hex/10%10)<<4;
	}
}

// 每月天数（非闰年）
static const uint8_t daysInMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

// 获取指定月份的天数（考虑闰年）
static uint8_t getDaysInMonth(uint8_t year, uint8_t month) {
    if (month < 1 || month > 12) return 0;
    
    uint8_t days = daysInMonth[month - 1];
    // 闰年2月多一天
    if (month == 2 && ((year % 4 == 0) && (year % 100 != 0 || year % 400 == 0))) {
        days += 1;
    }
    return days;
}

// 判断是否为闰年
static bool isLeapYear(uint8_t year) {
    return (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0);
}

// 计算从00年1月1日到指定日期的总天数
static uint32_t calculateDaysFromEpoch(uint8_t year, uint8_t month, uint8_t day) {
    uint32_t days = 0;
    
    // 累加往年天数
    for (uint8_t y = 0; y < year; y++) {
        days += 365 + (isLeapYear(y) ? 1 : 0);
    }
    
    // 累加当前年本月之前的天数
    for (uint8_t m = 1; m < month; m++) {
        days += getDaysInMonth(year, m);
    }
    
    // 加上当月天数
    days += day - 1;
    
    return days;
}

// 根据总天数计算星期几 (0-6, 0=星期日)
uint8_t calculateWeekday(uint32_t daysSinceEpoch) {
    // 00年1月1日是星期六(6)
    return (6 + daysSinceEpoch) % 7;
}

// 将time_count转换为time数组
void MathBsp_timeCountToTime(uint32_t time_count, uint8_t time[7]) {
    uint32_t seconds = time_count;
    const uint32_t secondsPerDay = 24 * 60 * 60;
    
    // 计算天数（从00年1月1日开始）
    uint32_t days = seconds / secondsPerDay;
    seconds %= secondsPerDay;
    
    // 计算时、分、秒
    time[4] = seconds / 3600;           // 小时
    seconds %= 3600;
    time[5] = seconds / 60;             // 分钟
    time[6] = seconds % 60;             // 秒
    
    // 计算年
    uint16_t year = 0;
    while (1) {
        uint32_t daysInYear = 365 + (isLeapYear(year) ? 1 : 0);
        if (days < daysInYear) break;
        days -= daysInYear;
        year++;
    }
    time[0] = year % 100;  // 只保留后两位（如2025年表示为25）
    
    // 计算月和日
    uint8_t month = 1;
    while (month <= 12) {
        uint32_t daysInThisMonth = getDaysInMonth(year, month);
        if (days < daysInThisMonth) break;
        days -= daysInThisMonth;
        month++;
    }
    time[1] = month;
    time[2] = days + 1;  // 日（从1开始）
    
    // 计算星期（0=星期日，1=星期一，...，6=星期六）
    time[3] = calculateWeekday(calculateDaysFromEpoch(year, month, time[2]));
}

// 校验time数组是否有效 -> 注意：本项目没有涉及星期的处理，故在时间检验的时候自动校准星期
bool MathBsp_validateTime(uint8_t time[7]) {
    // 校验年（假设范围0-99）
    if (time[0] > 99) return false;
    
    // 校验月
    if (time[1] < 1 || time[1] > 12) return false;
    
    // 校验日（动态计算当月最大天数）
    uint8_t maxDays = getDaysInMonth(time[0], time[1]);
    if (time[2] < 1 || time[2] > maxDays) return false;
    
    // 校验星期
    if (time[3] > 6) return false;
    
    // 校验计算出的星期与给定值是否一致
    uint32_t days = calculateDaysFromEpoch(time[0], time[1], time[2]);
		time[3] = calculateWeekday(days);
    
    // 校验时、分、秒
    if (time[4] > 23) return false;
    if (time[5] > 59) return false;
    if (time[6] > 59) return false;
    
    return true;
}    

// 将time数组转换为time_count
uint32_t MathBsp_timeToTimeCount(uint8_t time[7]) {
    if (!MathBsp_validateTime(time)) return 0;
    
    uint8_t year = time[0];
    uint8_t month = time[1];
    uint8_t day = time[2];
    uint8_t hour = time[4];
    uint8_t minute = time[5];
    uint8_t second = time[6];
    
    // 计算总天数
    uint32_t days = calculateDaysFromEpoch(year, month, day);
    
    // 转换为秒数（在函数内部定义secondsPerDay常量）
    const uint32_t secondsPerDay = 24 * 60 * 60;
    return days * secondsPerDay + hour * 3600 + minute * 60 + second;
}



/**
 * 比较两个uint8_t数组是否完全相同
 * @param arr1 第一个数组
 * @param arr2 第二个数组
 * @param length 要比较的元素数量
 * @return 相同返回1，不同返回0
 */
uint8_t MathBsp_CompareArrays(const uint8_t *arr1, const uint8_t *arr2, uint32_t length)
{
    for (uint32_t i = 0; i < length; i++)
    {
        if (arr1[i] != arr2[i])
        {
            return 1; // 发现不同元素，返回1
        }
    }
    return 0; // 所有元素都相同
}

//延时
void MathBsp_Sofdelayms(uint32_t time)
{
	for(uint32_t i = 0; i < time; i++)
	{
		for(volatile uint32_t j = 0; j < 80; j++);
	}
}
